import logging

import uiautomator2 as u2
import time
import os
import random
import serial
import threading
from datetime import datetime
from typing import Optional, Dict

# 全局共享资源
stop_event = threading.Event()


# 常量配置(提取硬编码内容)
class Config:
    MI_HOME_PACKAGE = "com.xiaomi.smarthome"
    MAIN_ACTIVITY = ".SmartHomeMainActivity"
    DEFAULT_SCREENSHOT_DIR = "./screenshots"
    LOG_FORMAT = "%(asctime)s-%(levelname)s-%(message)s"

    class MinHomeTester:
        def __init__(self, device_id, lock_name):
            self.d = u2.connect(device_id)
            self.lock_name = lock_name
            self.logger = self._setup_logger()
            self.prepare_dirs()

        def _setup_logger(self) -> logging.Logger:
            """配置日志系统"""
            logger = logging.getLogger(__name__)
            logger.setLevel(logging.INFO)
            # 文件日志
            file_name = datetime.now().strftime('%Y%m%d%H%M') + '_automation.log'
            file_handler = logger.FileHandler(file_name)

            file_handler.serFormatter(logger.Formatter(Config.LOG_FORMAT))
            # 控制台日志
            console_handler = logger.StreamHandler()

            console_handler.setFormatter(logger.Formatter(Config.LOG_FORMAT))
            logger.addHandler(file_handler)
            logger.addHandler(console_handler)
            return logger

    def _prepare_dirs(self):
        """创建必要目录"""
        os.makedirs(Config.DEFAULT_SCREENSHOT_DIR, exist_ok=True)

        def screenshot(self, sub_dir: str = "default") -> str:
            """通用截图方法"""
            timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
            dir_path = os.path.join(Config.DEFAULT_SCREENSHOT_DIR, sub_dir)
            os.makedirs(dir_path, exist_ok=True)
            save_path = os.path.join(dir_path, f"{timestamp}.jpg")
            self.d.screenshot().save(save_path)
            self.logger.info(f"Screenshot saved:{save_path}")
            return save_path

        def safe_click(self, selecto: Dict, timeout: int = 1) -> bool:
            """安全点击控件（修正版）"""

            try:
                # 等待元素存在
                if self.d(**selector).wait(timeout):
                    # 重新获取元素并点击
                    element = self.d(**selector)
                    element.click()
                    return True
                self.logger.warning(f"元素未找到:{selector}")
                return False
            except Exception as e:
                self.logger.error(f"点击失败:{str(e)}")
                return False

        def open_mihome(self) -> bool:
            """启动米家APP"""

        try:
            # 清理旧进程

            self.d.app_stop(package_name='com.xiaomi.smarthome')
            time.sleep(1)
            # 启动应用
            self.d.app_start(package_name='com,xiaomi.smarthome', activity='.SmartHomeMainActivity')
            time.sleep(1)

            self.d.wait_activity('.SmartHomeMainActivity')
            # 等待主界面
            if self.d(text="全屋").wait(timeout=10):
                self.logger.info("成功进入米家首页")
                return True
                self.logger.error("进入米家首页失败")
                return false
        except Exception as e:
            self.logger.error("启动米家APP异常:{str(e)}")
        return false

    def bluetooth_unlock_test(self, test_cycles: int, interval: int):
        """蓝牙开锁测试"""
        for cycle in range(1, test_cycles + 1):
            self.logger.info(f"==============第{cycle}次测试====================")
            try:
                # 启动米家应用，并进入插件
                if self.open_mihome():
                    # 进入门锁控制页
                    if not self.safe_click({"text": self.lock_name}, timeout=5):  # 延长超时
                        self.logger.error("未找到门锁，门锁名称不正确")
                        continue
                        ble_start = time.time()
                        if self.d(textMathches="稍后再说|安全守护中").wait(timeout=120):
                            ble_duration = time.time() - ble_start - 1.1
                        self.logger.info(f"蓝牙连接耗时:{ble_duration:.2f}秒")
                        if ble_duration > 6:
                            self_logger.warning("蓝牙连接超过6s，FAIL")
                        else:
                            self.logger.error("蓝牙连接超时120秒失败，FAIL")
                            self.screenshot("蓝牙连接超时截图")
                            continue
                            # 处理升级弹窗
                        if self.d(text="稍后再说").exists(timeout=5):
                            self.d(text="稍后再说").click()
                            self.logger.info("已关闭升级弹窗")
                        else:
                            self.logger.info("无法升级弹窗")
                    self.d(scrollable=True).scroll.toEnd()
                    time.sleep(1)
                    self.d(text="长按开锁").long_click(2)
                    # 验证开锁结果
                    unlock_start = time.time()
                    if self.d(textMatches="开锁成功").wait(timeout=5):  # 延长等待时间
                        self.logger.info(f"开锁成功,开锁耗时:{unlock_duration:.2f}秒")
                        # 检查门锁状态
                        self.d(scrollable=True).scroll.toBegining()
                        if self.d(text="已开锁").wait(timeout=2):
                            self.logger.info("门锁状态已正确")
                        elif self.d(text="已上锁").wait(timeout=2):
                            self.logger.error("门锁状态异常，FAIL")
                            self.screenshot("门锁状态异常截图")
                        else:
                            self.logger.error("门锁状态异常，FAIL")
                            self.screenshot("门锁状态异常截图")
                    else:
                        self.logger.error("门锁状态异常，FAIL")
                        self.screenshot("门锁状态异常截图")
                # 环境清理
                self.d.app_stop('com.xiao.smarthome')
                self._countdown(interval)  # 确保间隔准确
            except Exception as e:
                self.logger.error(f"测试异常：{str(e)}")  # 记录堆栈
                continue

    def Video_streaming_testchek(self):
        try:
            self.d.xpath(
                '//android.widget.ScrollView/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[2]/android.widget.ImageView[1]').get(
                timeout=20)
            time.sleep(3)
            self.logger.info(f"视频拉流成功")
            self.screenshot("视频拉流成功截图")
            return True
        except Exception as e:
            self.logger.error(f"视频拉流失败")
            self.screenshot("视频拉流失败截图")

    def Video_streaming_testchek(self, test_cycles, interval):
        """视频拉流测试"""
        for cycle in range(1, test_cycles + 1):
            self.logger.info(f"==============第{cycle}次测试================")
            try:
                if self.open_mihome():
                    # 进入门锁控制页
                    if not self.safe_click({"text": self.lock_name}, timeout=5):  # 延长超时间
                        self.logger.error("未找到门锁，门锁名称不正确")
                        continue
                        # 处理升级弹窗
                    if self.d(text="稍后再说").exists(timeout=5):
                        self.d(text="稍后再说").click()
                        self.loggrt.info("关闭升级弹窗")
                    else:
                        self.logger.info("无法升级弹窗")
                    if self.d(text="查看实时画面").wait(timeout=5):
                        self.lgger.info("设备已经打开实时画面")
                        # 执行拉流操作
                        self.d.xpath('//*[@text="查看实时画面"]').click()
                        if self.safe_click({"text": "点击继续"}, timeout=5):
                            self.logger.info("流量点击视频拉流")
                            self.Video_streaming_testchek()
                        else:
                            self.logger.info("wifi点击视频拉流")
                            self.Video_streaming_testchek()
                    else:
                        self.logger.error("设备未打开实时画面，或者有可能触发逗留")
                        self.d.click(0.437, 0.436)
                        if self.safe_click({"text": "点击继续"}, timeout=5):
                            self.logger.info("流量点击视频拉流")
                            self.Video_streaming_testchek()
                        else:
                            self.logger.info("wifi点击视频拉流")
                            self.Video_streaming_testchek()
                            # 清理环境
                            # 清理旧进程
                            self.d.app_stop(package_name='com.xiaomi.smarthome')
                            self._countdown(interval)
            except Exception as e:
                self.logger.error(f"测试流程异常:{str(e)}")
                continue

    def mitest_added_delete(self, test_cycles, interval, lock_name):
        """设备添加&删除"""
        # 启动线程
        read_thread = threading.Thread(target=monitor.read_from_serial)
        # send_thread=threading.Thread(target=monitor.send_to_serial(command))
        read_thread.start()
        # send_thread,start()
        for cycle in range(1, test_cycles + 1):
            self.logger.info(f"===============第{cycle}次测试===============")
            try:
                # 重置操作
                controller.relaytest("K", long_or_cilk=5)
                number2 = "0F DE 00 81 00 09 00 31 31 34 37 32 35 38 23 01 04"
                # 发指令
                monitor.send_to_serial(command=numbers2)
                time.sleep(5)
                if self.open_mihome():
                    if self.d(textMatcher=f".*{str(lock_name)}.*").wait(timeout=5):
                        self.d(textMatches=f".*{str(lock_name)}.*").click()
                        if self.d(text="删除设备").wait(timeout=30):
                            self.d(text="删除设备").click()
                        else:
                            self.logger.info("设备插件已删除")
                            continue
                        self.d(textMatches=f".*{str(lock_name)}.*").click()
                        time.sleep(3)
                        self.d.click(0.482, 0.934)
                        for i in range(1, 13):
                            self.d(resourceld="com.xiaomi.smarthome:id/eys").click()
                            a = self.d(resourceld="com.xiaomi.smarthome:id/co9").get_text()
                            b = self.d(resourceld="com.xiaomi.smarthome:id/co_").get_text()
                            c = self.d(resourceld="com.xiaomi.smarthome:id/coa").get_text()
                            d = self.d(resourceld="com.xiaomi.smarthome:id/cob").get_text()
                            e = self.d(resourceld="com.xiaomi.smarthome:id/coc").get_text()
                            f = self.d(resourceld="com.xiaomi.smarthome:id/cod").get_text()
                            number = "0F DE 00 81 00 08 00" + "3" + str(a) + "3" + str(b) + "3" + str(c) + "3" + str(
                                d) + "3" + str(e) + "3" + str(f) + " 23 01 04"
                            # 发指令
                            monitor.send_to_serial(command=number)
                            if self.d(text="设备添加成功").wait(timeout=30):
                                self.loggrer.info("设备添加成功")
                                time.sleep(5)
                                self.d(text="卧室").click()
                                time.sleep(2)
                                self.d.click(0.482, 0.934)
                                time.sleep(2)
                                self.d.click(0.482, 0.934)
                                time.sleep(5)
                                self.d(resourceld="com.xiaomi.smarthome:id/ij").click()
                                time.sleep(10)
                                if self.d(textContains="无法上锁").wait(timeout=30)
                                    self.d.click(0.482, 0.934)
                                    num = "147258"
                                    time.sleep(2)
                                    self.d.press("back")
                                    self.d.xpath(
                                        '//*[@resource-id="com.xiaomi.smarthome:id/ax3"]/android.widger.FrameLayout[2]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[2]/android.view.ViewGroup[1]/').set_text(
                                        num)
                                    time.sleep(1)
                                    self.d.click(0.482, 0.934)
                                    time.sleep(1)
                                    self.d.xpath(
                                        '//*[@resource-id="com.xiaomi.smarthome:id/ax3"]/android.widger.FrameLayout[2]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[2]/android.view.ViewGroup[2]/').click()
                                    time.sleep(1)
                                    self.d.press("back")
                                    self.d.xpath(
                                        '//*[@resource-id="com.xiaomi.smarthome:id/ax3"]/android.widger.FrameLayout[2]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[2]/android.view.ViewGroup[1]/').set_text(
                                        num)
                                    time.sleep(1)
                                    self.d.click(0.482, 0.934)
                                    time.sleep(1)
                                    self.d.xpath(
                                        '//*[@resource-id="com.xiaomi.smarthome:id/ax3"]/android.widger.FrameLayout[2]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[2]/android.view.ViewGroup[2]/').click()
                                    if self.d(text="添加密码成功").wait(timeout=5):
                                        self.logger.info("添加密码成功")
                                    else:
                                        self.logger.info("添加密码失败")
                                        self.screenshot("添加密码失败截图")
                                else:
                                    self.logger.error("蓝牙没有连上无法添加用户")
                                    controller.relaytest("K", long_or_click=5)
                                # 发指令
                                monitor.send_to_serial(command=number2)
                                if self.d(text="删除设备").wait(timeout=5)
                                    self.d(text="删除设备").click()
                                    self._countdown(interval)
                            else:
                                self.logger.error("设备绑定失败")
                                self.screenshot("设备绑定失败截图")
                                # 环境清理
                                self.d.app_stop('com.xiaomi.smarthome')
                                self._countdown(interval)
                                # 确保间隔准确
                                pass
                        else:
                            self.logger.error("异常跳过")
                            self.screenshot("设备绑定异常跳过截图")
                            # 环境清理
                            self.d.app_stop('com.xiaomi.smarthome')
                            self._countdown(interval)
                            pass

            except Exception as e:
                self.logger.error(f"测试流程异常{str(e)}")
                self.logger.error("异常跳过")
                continue

    def mitest_added_delete_power(self, test_cycle, interval, lock_name):
        """设备添加&删除"""
        # 启动线程
        read_thread = threading.Thread(target=monitor.read_from_serial)
        # send_thread = threading.Thread(target=monitor.read_from_serial(command))
        read_thread.start()
        # send_thread.start()
        for cycle in range(1, test_cycle + 1):
            self.logger.info(f"===============第{cycle}次测试===============")
            try:
                # 上电操作
                power_test.send_command("<07000000000>")
                # power_test.power_relatTestlest("<07000000000>")
                time.sleep(5)
                # 重置操作
                contorller.relaytest("K", long_or_click=5)
                time.sleep(1)
                number2 ="0F DE 00 81 00 09 00 31 31 34 37 32 35 38 23 01 04"
                #发指令
            monitor.send_to_serial(command=number2)
            time.sleep(5)
            if self.open_mihome():
                if self.d(textMatches=f".*{str(lock_name)}.*").wait(timeout=5):
                    self.d(textMatches=f".*{str(lock_name)}.*").click()
                    if self.d(text="删除设备").wait(timeout=30):
                        self.d(text="删除设备").click()
                    else:
                        self.logger.info("设备插件已删除")
                        continue
                self.d(resourceId="com.xiaomi.smarthome:id/gr").click()
                time.sleep(1)
                self.d(text="添加设备").click()
                controller.relaytest("M", long_or_click=5)
                time.sleep(5)
                self.d(textMatches=f".*{str(lock_name)}.*").click()
                time.sleep(8)
                self.d.click(0.482, 0.934)
                for i in range(1, 13):
                    self.d(resourceId="com.xiaomi.smarthome:id/eys").click()
                a = self.d(resourceId="com.xiaomi.smarthome:id/co9").get_text()
                b = self.d(resourceId="com.xiaomi.smarthome:id/co_").get_text()
                c = self.d(resourceId="com.xiaomi.smarthome:id/coa").get_text()
                d = self.d(resourceId="com.xiaomi.smarthome:id/cob").get_text()
                e = self.d(resourceId="com.xiaomi.smarthome:id/coc").get_text()
                f = self.d(resourceId="com.xiaomi.smarthome:id/cod").get_text()

                number = "0F DE 00 81 00 08 00" + " 3" + str(a) + " 3" + str(b) + " 3" + str(c) + " 3" + str(
                    d) + " 3" + str(e) + " 3" + str(f) + " 23 01 04"
                # 发指令
                monitor.send_to_serial(command=number)
                if self.d(text="设备添加成功").wait(timeout=30):
                    self.logger.info("设备添加成功")
                    time.sleep(5)
                    self.d(text="卧室").click()
                    time.sleep(2)
                    self.d.click(0.482, 0.934)
                    time.sleep(2)
                    self.d.click(0.482, 0.934)
                    time.sleep(5)
                    self.d(resourceId="com.xiaomi.smarthome:id/ij").click()
                    time.sleep(10)
                    if self.d(textContains="无法上锁").wait(timeout=30):
                        self.d.click(0.482, 0.934)
                        num = "1147258"
                        time.sleep(2)
                        self.d.press("back")
                        self.d.xpath(
                            '//*[@resource-id="com.xiaomi.smarthome:id/ax3"]/android.widget.FrameLayout[2]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[2]/android.view.ViewGroup[1]').set_text(
                            num)
                        time.sleep(1)
                        self.d.click(0.482, 0.934)
                        time.sleep(1)
                        self.d.xpath(
                            '//*[@resource-id="com.xiaomi.smarthome:id/ax3"]/android.widget.FrameLayout[2]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[2]/android.view.ViewGroup[2]').click()
                        time.sleep(1)
                        self.d.press("back")
                        self.d.xpath(
                            '//*[@resource-id="com.xiaomi.smarthome:id/ax3"]/android.widget.FrameLayout[2]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[2]/android.view.ViewGroup[1]').set_text(
                            num)
                        time.sleep(1)
                        self.d.click(0.482, 0.934)
                        time.sleep(1)
                        self.d.xpath(
                            '//*[@resource-id="com.xiaomi.smarthome:id/ax3"]/android.widget.FrameLayout[2]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[1]/android.view.ViewGroup[2]/android.view.ViewGroup[2]').click()
                        if self.d(text="添加密码成功").wait(timeout=5):
                            self.logger.info("添加密码成功")
                        else:
                            self.logger.info("添加密码失败")
                            self.screenshot("添加密码失败截图")
                    else:
                        self.logger.error("蓝牙没连上无法添加用户")
                    controller.relaytest("K", long_or_click=5)
                    # 发指令
                    monitor.send_to_serial(command=number2)
                    time.sleep(5)
                    # 下电操作
                    power_test.send_command("<08000000000>")
                    # power_test.power_relayTestlest("<08000000000>")
                    time.sleep(5)
                    if self.d(text="删除设备").wait(timeout=5):
                        self.d(text="删除设备").click()
                        self._countdown(interval)
                else:
                    self.logger.error("设备绑定失败")
                    self.screenshot("设备绑定失败截图")
                    # 环境清理
                    self.d.app_stop('com.xiaomi.smarthome')
                    self._countdown(interval)  # 确保间隔准确
                    pass
            else:
                self.logger.error("异常跳过")
                self.screenshot("设备绑定异常跳过截图")
                # 环境清理
                self.d.app_stop('com.xiaomi.smarthome')
                self._countdown(interval)  # 确保间隔准确
                pass

        except Exception as e:
        self.logger.error(f"测试流程异常: {str(e)}")
        self.logger.error("异常跳过")
        continue
    def _countdown(self,seconds:int):
        """倒计时等待"""
        self.logger.info(f"等待 {seconds} 秒...")
        for remaining in range(seconds, 0, -1):
            time.sleep(1)
            if remaining % 10 == 0:
                self.logger.info(f"剩余等待时间: {remaining}s")

    def generate_random_str(self):
        length = random.randint(6, 10)
        return ''.join(str(random.randint(0, 9)) for _ in range(length))

    class RelayController:
        def __init__(self, port, baudrate=9600):
            """
            初始化串口连接
            :param port: 串口号，如 'COM3' 或 '/dev/ttyUSB0'
            :param baudrate: 波特率，默认9600
            """
            self.port = port
            self.baudrate = baudrate
            self.ser = None
            self.open()

        def open(self):
            """打开串口连接"""
            if not self.ser or not self.ser.is_open:
                self.ser = serial.Serial(
                    port=self.port,
                    baudrate=self.baudrate,
                    bytesize=serial.EIGHTBITS,
                    parity=serial.PARITY_NONE,
                    stopbits=serial.STOPBITS_ONE,
                    timeout=1
                )

        def close(self):
            """关闭串口连接"""
            if self.ser and self.ser.is_open:
                self.ser.close()

        def send_command(self, command, delay=0.1):
            """
            发送命令到继电器
            :param command: 字符串或字节类型的命令
            :param delay: 发送后等待时间（秒）
            """
            if not self.ser.is_open:
                self.open()

            # 统一转换为字节格式发送
            if isinstance(command, str):
                cmd_bytes = command.encode('utf-8')
            else:
                cmd_bytes = command

            self.ser.write(cmd_bytes)
            time.sleep(delay)  # 确保设备响应

        def relaytest(self, end, long_or_click):
            try:
                controller.send_command(end)
                time.sleep(long_or_click)
                controller.send_command("O")
                # print("继电器操作")
            except Exception as e:
                print(f"继电器测试异常,{str(e)}")
                pass

        def relayTestlest(self, test_cycles, Max):
            for cycle in range(1, test_cycles + 1):
                print(f"========== 第 {cycle} 次测试 ==========")
                try:
                    controller.send_command("<07000000000>")
                    random_int = random.randint(0, Max)
                    print("上电等待" + str(random_int) + "秒")
                    time.sleep(random_int)
                    controller.send_command("<08000000000>")
                    random_int = random.randint(0, Max)
                    print("下电等待" + str(random_int) + "秒")
                    time.sleep(random_int)
                    print("通断电操作")
                except Exception as e:
                    print(f"继电器测试异常,{str(e)}")
                    continue

    class RelayController_Power:
        def __init__(self, port, baudrate=9600):
            """
            初始化串口连接
            :param port: 串口号，如 'COM3' 或 '/dev/ttyUSB0'
            :param baudrate: 波特率，默认9600
            """
            self.port = port
            self.baudrate = baudrate
            self.ser2 = None
            self.open1()

        def open1(self):
            """打开串口连接"""
            if not self.ser2 or not self.ser2.is_open:
                self.ser2 = serial.Serial(
                    port=self.port,
                    baudrate=self.baudrate,
                    bytesize=serial.EIGHTBITS,
                    parity=serial.PARITY_NONE,
                    stopbits=serial.STOPBITS_ONE,
                    timeout=1
                )

        def send_command(self, command, delay=0.1):
            """
            发送命令到继电器
            :param command: 字符串或字节类型的命令
            :param delay: 发送后等待时间（秒）
            """
            if not self.ser2.is_open:
                self.open1()

            # 统一转换为字节格式发送
            if isinstance(command, str):
                cmd_bytes = command.encode('utf-8')
            else:
                cmd_bytes = command

            self.ser2.write(cmd_bytes)
            time.sleep(delay)  # 确保设备响应

    class SerialMonitor:
        def __init__(self, port, log_file):
            # 初始化串口参数
            self.serial_port = port
            self.baudrate = 115200
            self.log_file = log_file

            # 创建串口对象
            self.ser1 = serial.Serial(
                port=self.serial_port,
                baudrate=self.baudrate,
                timeout=1
            )

            # 线程控制标志
            self.running = True

            # 初始化日志文件（追加模式）
            self.log = open(self.log_file, "a", encoding='utf-8', errors='replace')
            # print(f"Logging to {self.log_file}")

        def read_from_serial(self):
            """持续读取串口数据并写入日志文件"""
            while self.running:
                try:
                    # 读取串口数据
                    if self.ser1.in_waiting > 0:
                        # 读取数据（等待直到有数据）
                        #                     data = ser.readline()  # 按行读取，适合文本协议
                        #                     if data:
                        #                         timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
                        #                         try:
                        #                             decoded = data.decode('utf-8', errors='replace').strip()
                        #                             log_entry = f"[{timestamp}] {decoded}\n"
                        #                         except UnicodeDecodeError:
                        #                             hex_data = data.hex().upper()
                        #                             log_entry = f"[{timestamp}] HEX [{hex_data}]\n"
                        #
                        #                         f.write(log_entry)
                        #                         f.flush()
                        #                     time.sleep(0.01)  # 适当降低CPU占用
                        data = self.ser1.read(self.ser1.in_waiting)
                        decoded_data = data.decode('utf-8', errors='replace').strip()
                        # 写入日志文件
                        timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3]
                        self.log.write(f"[{timestamp}] {decoded_data}\n")
                        self.log.flush()  # 确保实时写入
                        time.sleep(0.01)  # 适当降低CPU占用
                        # 输出到控制台（可选）
                        # print(decoded_data, end='')

                except Exception as e:
                    print(f"Error reading serial: {str(e)}")
                    break

        def send_to_serial(self, command):
            """发送命令到串口"""
            try:
                # 将十六进制字符串转换为字节数据
                byte_data = bytes.fromhex(command)
                self.ser1.write(byte_data)
                # print(f"Sent: {command}")
            except Exception as e:
                print(f"Error sending command: {str(e)}")

        def close(self):
            """清理资源"""
            self.running = False
            time.sleep(0.1)  # 等待线程退出
            self.ser1.close()
            self.log.close()
            print("\nResources released")

    if __name__ == "__main__":
        # 用户输入
        print("如果无法正常运行，请先尝试cmd控制台执行：pip install uiautomator2==2.16.25\n"
              "请在关门的状态下运行，确认门锁状态为：已上锁\n"
              "如果要计算耗时，需要手动开启手机录屏功能，以便视频分析耗时\n"
              "请选择需要运行的脚本编号\n"
              "1、蓝牙连接开门脚本\n"
              "2、视频拉流脚本，需要关闭蓝牙，打开直播模式\n"
              "3、设备绑定解绑，需要关闭小米手机安全键盘\n"
              "4、程控电源随机通断电\n"
              "5、程控电源+重置\n")
        file_name_MCU = datetime.now().strftime('%Y%m%d%H%M') + '_MCU.log'
        tester_name = int(input("请输入测试项目: "))
        test_cycles = int(input("请输入测试次数: "))

        # 执行测试
        if tester_name == 1:
            device_id = input("请输入设备ID: ").strip()
            lock_name = input("请输入门锁名称(小米智能门锁 2 猫眼版): ").strip()
            interval = int(input("请输入间隔时间(s): "))
            tester = MiHomeTester(device_id, lock_name)
            tester.bluetooth_unlock_test(test_cycles, interval)
            input("按回车键退出...")  # Python 3
        elif tester_name == 2:
            device_id = input("请输入设备ID: ").strip()
            lock_name = input("请输入门锁名称(小米智能门锁 2 猫眼版): ").strip()
            interval = int(input("请输入间隔时间(s): "))
            tester = MiHomeTester(device_id, lock_name)
            tester.Video_streaming_test(test_cycles, interval)
            input("按回车键退出...")  # Python 3
        elif tester_name == 3:
            device_id = input("请输入设备ID: ").strip()
            # lock_name = input("请输入门锁名称(小米智能门锁 2 猫眼版): ").strip()
            port_mcu = input("请输入MCU端口号(如COM3):").strip()
            port_relay = input("请输入继电器串口号(如COM3):").strip()
            interval = int(input("请输入间隔时间(s): "))
            lock_name = input("请输入门锁类型(猫眼版/大屏猫眼版/指静脉增强版): ").strip()
            monitor = SerialMonitor(port=port_mcu, log_file=file_name_MCU)
            controller = RelayController(port=port_relay, baudrate=9600)
            tester = MiHomeTester(device_id, lock_name="小米智能门锁 2 猫眼版")
            tester.mitest_added_delete(test_cycles, interval, lock_name=lock_name)  # 多线程
            input("按回车键退出...")  # Python 3
        elif tester_name == 4:
            port3 = input("请输入程控电源端口号(如COM3):").strip()
            Max = int(input("请输入，等待最大时长单位（s）"))
            controller = RelayController(port=port3, baudrate=9600)
            controller.relayTestlest(test_cycles, Max)
            input("按回车键退出...")
        elif tester_name == 5:
            device_id = input("请输入设备ID: ").strip()
            port_mcu = input("请输入MCU端口号(如COM3):").strip()
            port_relay = input("请输入继电器串口号(如COM3):").strip()
            power_relay = input("请输入程控电源串口号(如COM3):").strip()
            interval = int(input("请输入间隔时间(s): "))
            lock_name = input("请输入门锁类型(猫眼版/大屏猫眼版/指静脉增强版): ").strip()
            monitor = SerialMonitor(port=port_mcu, log_file=file_name_MCU)
            controller = RelayController(port=port_relay, baudrate=9600)
            power_test = RelayController_Power(port=power_relay, baudrate=9600)
            tester = MiHomeTester(device_id, lock_name="小米智能门锁 2 猫眼版")
            tester.mitest_added_delete_power(test_cycles, interval, lock_name=lock_name)  # 多线程
            input("按回车键退出...")  # Python 3
